package com.settlement.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.settlement.system.common.constant.SystemConstants;
import com.settlement.system.common.enums.BorrowingStatusEnum;
import com.settlement.system.common.model.Option;
import com.settlement.system.common.util.DateUtils;
import com.settlement.system.common.util.SecurityUtils;
import com.settlement.system.job.JobUtils;
import com.settlement.system.mapper.*;
import com.settlement.system.model.entity.*;
import com.settlement.system.model.query.BillPageQuery;
import com.settlement.system.model.query.BillSummaryQuery;
import com.settlement.system.model.vo.SysBillSummaryVO;
import com.settlement.system.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 标准账单汇总 服务实现类
 * </p>
 *
 * @author huangrensen
 * @since 2023-08-05
 */
@Service
@RequiredArgsConstructor
public class SysBillSummaryServiceImpl extends ServiceImpl<SysBillSummaryMapper, SysBillSummary> implements SysBillSummaryService {

    private final static Logger logger = LoggerFactory.getLogger(SysBillSummaryServiceImpl.class);
    private final SysBillSummaryMapper sysBillSummaryMapper;

    private final SysBillService sysBillService;

    private final SysFileAuditService fileAuditService;

    private final SysCompanyService sysCompanyService;

    private final SysCompanyMapper sysCompanyMapper;
    private final SysStoreMapper sysStoreMapper;

    private final SysDictTypeService sysDictTypeService;

    private final SysSubjectsMapper subjectsMapper;

    private final SysAccessoryMapper sysAccessoryMapper;
    private final SysUserMapper sysUserMapper;
    private final SysSubjectsService sysSubjectsService;

    @Override
    public void removeAll(String tableName) {
        sysBillSummaryMapper.deleteAll(tableName);
    }

    @Override
    public void deleteTable(String tableName) {
        sysBillSummaryMapper.deleteTable(tableName);
    }

    @Override
    public Page<SysBillSummaryVO> getPage(BillSummaryQuery queryParams) {
        // 查询参数
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        // 查询数据
        String tableName = "sys_bill_summary_%s".formatted(queryParams.getBillMonth());
        queryParams.setTableName(tableName);
        if (!fileAuditService.existTable(tableName)) {
            return new Page<>(pageNum, pageSize);
        }
        Page<SysBillSummary> page = new Page<>(pageNum, pageSize);
        List<SysCompany> sysCompanyList = sysCompanyService.list();
        Page<SysBillSummary> sysBillSummaryPage = this.baseMapper.getPage(page, queryParams);
        if (sysBillSummaryPage.getRecords().size() == 0) {
            return new Page<>(pageNum, pageSize);
        }
        // 科目
        List<SysSubjects> subjectsList = sysSubjectsService.list(new LambdaQueryWrapper<SysSubjects>().in(SysSubjects::getLastCode,
                page.getRecords().stream().map(SysBillSummary::getLastCode).toList()));
        Page<SysBillSummaryVO> pageVo = new Page<>(pageNum, pageSize);
        BeanUtil.copyProperties(page, pageVo, "records");
        List<SysBillSummaryVO> vos = new ArrayList<>();
        for (SysBillSummary record : sysBillSummaryPage.getRecords()) {
            SysBillSummaryVO vo = new SysBillSummaryVO();
            BeanUtil.copyProperties(record, vo, "accessory");
            sysCompanyList.stream().filter(sysCompany -> sysCompany.getCode().equals(vo.getReceiveCompany()))
                    .findFirst()
                    .ifPresent(sysCompany -> vo.setReceiveCompany(sysCompany.getName()));
            subjectsList.stream().filter(sysSubject -> sysSubject.getLastCode().equals(vo.getLastCode()))
                            .findFirst()
                                    .ifPresent(sysSubject -> vo.setLastName(sysSubject.getLastName()));
            if(StringUtils.hasText(record.getAccessory())){
                vo.setAccessory(JSONObject.parseObject(record.getAccessory(), Map.class));
            }
            vos.add(vo);
        }
        pageVo.setRecords(vos);
        return pageVo;
    }

    @Override
    public int createTable(String tableName) {
        return this.baseMapper.createTable(tableName);
    }

    @Override
    public void createOrUpdate(List<SysBillSummary> sysBillSummaryList) {
        BillSummaryQuery query;
        for (SysBillSummary sysBillSummary : sysBillSummaryList) {
            query = new BillSummaryQuery();
            query.setStoreId(sysBillSummary.getStoreId());
            query.setBillProject(sysBillSummary.getBillProject());
            query.setAccessoryText(sysBillSummary.getAccessoryText());
            query.setTableName(sysBillSummary.getTableName());
            List<SysBillSummary> billSummaryList = this.sysBillSummaryMapper.getList(query);
            if (billSummaryList.size() > 0) {
                SysBillSummary summary = billSummaryList.get(0);
                // 汇总账单金额
                summary.setBillAmount(summary.getBillAmount().add(sysBillSummary.getBillAmount()));
                // 汇总税额
                summary.setTaxAmount(summary.getTaxAmount().add(sysBillSummary.getTaxAmount()));
                // 不含税金额
                summary.setUnTaxAmount(summary.getBillAmount().subtract(summary.getTaxAmount()).setScale(2
                        , RoundingMode.UP));
                summary.setTableName(query.getTableName());
                logger.info("需要更新的参数：【%s】".formatted(summary.toString()));
                this.baseMapper.update(summary);
            } else {
                sysBillSummary.setId(null);
                logger.info("需要保存的参数：【%s】".formatted(sysBillSummary.toString()));
                this.baseMapper.insertData(sysBillSummary);
            }
        }
    }

    @Override
    public List<Map<String, String>> listSummary(BillSummaryQuery queryParams) {
        // 封装数据
        List<Map<String, String>> data = new ArrayList<>();
        // 查询数据
        String tableName = "sys_bill_summary_%s".formatted(queryParams.getBillMonth());
        queryParams.setTableName(tableName);
        if (!fileAuditService.existTable(tableName)) {
            return data;
        }
        List<SysBillSummary> summaryList = this.baseMapper.getList(queryParams);
        // 辅助项
        SysAccessory accessoryData = sysAccessoryMapper.selectList(null).get(0);
        // 取出所有的店铺
        List<SysStore> storeList = sysStoreMapper.selectList(new LambdaQueryWrapper<SysStore>().in(SysStore::getId,
                summaryList.stream().map(SysBillSummary::getStoreId).toList()));
        // 取出所有的入账主体
        List<SysCompany> companyList = sysCompanyMapper.selectList(new LambdaQueryWrapper<SysCompany>().in(SysCompany::getCode,
                summaryList.stream().map(SysBillSummary::getReceiveCompany).toList()));
        // 平台
        List<Option> optionList = sysDictTypeService.listDictItemsByTypeCode(SystemConstants.PLATFORM_KEY);
        // 科目
        List<String> codeList = new ArrayList<>();
        for (SysBillSummary sysBillSummary : summaryList) {
            codeList.add(sysBillSummary.getLastCode());
            codeList.add(sysBillSummary.getOtherLastCode());
        }
        List<SysSubjects> subjectsList = subjectsMapper.selectList(new LambdaQueryWrapper<SysSubjects>().in(SysSubjects::getLastCode, codeList));

        SysStore store;
        Option option;
        SysCompany company;
        String projectName = "";
        SysSubjects sysSubjects;
        BillPageQuery billPageQuery;
        for (SysBillSummary sysBillSummary : summaryList) {
            Map<String, String> item = new HashMap<>();
            // 先插入一条借方数据
            // 平台渠道
            store = storeList.stream().filter(sysStore -> sysStore.getId().equals(sysBillSummary.getStoreId()))
                    .findFirst()
                    .orElse(null);
            if (store != null) {
                String platformKey = store.getStoreKey();
                option =
                        optionList.stream().filter(o -> o.getValue().equals(platformKey)).findFirst().orElse(null);
                if (option != null) {
                    item.put("平台渠道", option.getLabel());
                }
            }
            // 汇总ID
            item.put("汇总ID", sysBillSummary.getSysBillId());
            // 核算账簿编码
            company = companyList.stream().filter(sysCompany -> sysCompany.getCode().equals(sysBillSummary.getReceiveCompany()))
                    .findFirst().orElse(null);
            if (company != null) {
                // 入账主体
                item.put("入账主体", company.getName());
                item.put("核算账簿编码", company.getBookCode());
            }
            // 制单人
            SysUser user = sysUserMapper.selectById(SecurityUtils.getUserId());
            item.put("制单人", user.getNickname());
            // 制单日期
            item.put("制单日期", DateUtils.getDateString(DateUtils.crossDf));
            // 科目编码
            item.put("科目编码", sysBillSummary.getLastCode());
            // 摘要
            if (store != null) {
                sysSubjects = subjectsList.stream().filter(sysSubject -> sysSubject.getLastCode().equals(sysBillSummary.getLastCode())).findFirst().orElse(null);
                if (sysSubjects != null) {
                    projectName = sysSubjects.getAccountingProject();
                    // 原币借方金额
                    if (BorrowingStatusEnum.JIE.getValue().equals(sysSubjects.getBorrowing())) {
                        item.put("原币借方金额", sysBillSummary.getBillAmount().setScale(2, RoundingMode.UP).toPlainString());
                        item.put("本币借方金额", sysBillSummary.getBillAmount().setScale(2, RoundingMode.UP).toPlainString());
                    } else {
                        item.put("原币贷方金额", sysBillSummary.getBillAmount().setScale(2, RoundingMode.UP).toPlainString());
                        item.put("本币贷方金额", sysBillSummary.getBillAmount().setScale(2, RoundingMode.UP).toPlainString());
                    }
                }
                item.put("摘要", "%s_%s".formatted(store.getFinanceSystemStoreName(), projectName));
            }
            // 币种
            item.put("币种", "本币");
            // 业务日期
            item.put("会计期间", sysBillSummary.getBillDate());
            // 凭证类型
            item.put("凭证类型", sysBillSummary.getBillProject());
            // 辅助项
            if (StringUtils.hasText(sysBillSummary.getAccessory())) {
                Map<String, String> accessory = JSONObject.parseObject(sysBillSummary.getAccessory(), Map.class);
                if (accessory.containsKey(accessoryData.getAccessoryName1())) {
                    item.put(accessoryData.getAccessoryName1(), accessory.get(accessoryData.getAccessoryName1()));
                }
                if (accessory.containsKey(accessoryData.getAccessoryName2())) {
                    item.put(accessoryData.getAccessoryName2(), accessory.get(accessoryData.getAccessoryName2()));
                }
                if (accessory.containsKey(accessoryData.getAccessoryName3())) {
                    item.put(accessoryData.getAccessoryName3(), accessory.get(accessoryData.getAccessoryName3()));
                }
                if (accessory.containsKey(accessoryData.getAccessoryName4())) {
                    item.put(accessoryData.getAccessoryName4(), accessory.get(accessoryData.getAccessoryName4()));
                }
                if (accessory.containsKey(accessoryData.getAccessoryName5())) {
                    item.put(accessoryData.getAccessoryName5(), accessory.get(accessoryData.getAccessoryName5()));
                }
                if (accessory.containsKey(accessoryData.getAccessoryName6())) {
                    item.put(accessoryData.getAccessoryName6(), accessory.get(accessoryData.getAccessoryName6()));
                }
                if (accessory.containsKey(accessoryData.getAccessoryName7())) {
                    item.put(accessoryData.getAccessoryName7(), accessory.get(accessoryData.getAccessoryName7()));
                }
                if (accessory.containsKey(accessoryData.getAccessoryName8())) {
                    item.put(accessoryData.getAccessoryName8(), accessory.get(accessoryData.getAccessoryName8()));
                }
                if (accessory.containsKey(accessoryData.getAccessoryName9())) {
                    item.put(accessoryData.getAccessoryName9(), accessory.get(accessoryData.getAccessoryName9()));
                }
            }
            data.add(item);
            // 对方
            tableName = "sys_bill_%s".formatted(queryParams.getBillMonth());
            billPageQuery = new BillPageQuery();
            billPageQuery.setTableName(tableName);
            billPageQuery.setSummaryId(sysBillSummary.getSysBillId());
            List<SysBill> billList = sysBillService.getList(billPageQuery);
            // 对方的分组规则是科目+辅助项
            for (SysBill sysBill : billList) {
                // 先计算辅助项(暂时放置在这个字段供下面分组使用)
                sysBill.setAccessory(JobUtils.concatOtherAccessoryStr(sysBill, accessoryData));
            }
            // 分组（科目+辅助项）
            Map<String, List<SysBill>> collect = billList.stream().collect(Collectors.groupingBy(sysBill -> sysBill.getOtherLastCode() + sysBill.getAccessory()));
            SysStore finalStore = store;
            collect.forEach((key, groupData) -> {
                Map<String, String> groupItem = new HashMap<>();
                groupItem.put("平台渠道", item.get("平台渠道"));
                groupItem.put("核算账簿编码", item.get("核算账簿编码"));
                groupItem.put("入账主体", item.get("入账主体"));
                groupItem.put("制单人", item.get("制单人"));
                groupItem.put("制单日期", item.get("制单日期"));
                // 科目编码
                groupItem.put("科目编码", groupData.get(0).getOtherLastCode());
                BigDecimal total = BigDecimal.ZERO;
                for (SysBill groupDatum : groupData) {
                    total = total.add(groupDatum.getBillAmount());
                }
                // 摘要
                SysSubjects subjects =
                        subjectsList.stream().filter(sysSubject -> sysSubject.getLastCode().equals(sysBillSummary.getOtherLastCode())).findFirst().orElse(null);
                if (subjects != null) {
                    groupItem.put("摘要", "%s_%s".formatted(finalStore.getFinanceSystemStoreName(), subjects.getAccountingProject()));
                    // 凭证类型
                    groupItem.put("凭证类型", "%s:%s_%s_%s".formatted(subjects.getBorrowing(), subjects.getAccountingProject(),
                            subjects.getLastCode(),
                            subjects.getLastName()));
                    // 原币借方金额
                    if (BorrowingStatusEnum.JIE.getValue().equals(subjects.getBorrowing())) {
                        groupItem.put("原币借方金额", total.setScale(2, RoundingMode.UP).toPlainString());
                        groupItem.put("本币借方金额", total.setScale(2, RoundingMode.UP).toPlainString());
                    } else {
                        groupItem.put("原币贷方金额", total.setScale(2, RoundingMode.UP).toPlainString());
                        groupItem.put("本币贷方金额", total.setScale(2, RoundingMode.UP).toPlainString());
                    }
                }
                // 币种
                groupItem.put("币种", "本币");
                // 业务日期
                groupItem.put("会计期间", sysBillSummary.getBillDate());
                // 辅助项
                if (StringUtils.hasText(groupData.get(0).getOtherAccessory())) {
                    Map<String, String> accessory = JSONObject.parseObject(groupData.get(0).getOtherAccessory(), Map.class);
                    if (accessory.containsKey(accessoryData.getAccessoryName1())) {
                        groupItem.put(accessoryData.getAccessoryName1(), accessory.get(accessoryData.getAccessoryName1()));
                    }
                    if (accessory.containsKey(accessoryData.getAccessoryName2())) {
                        groupItem.put(accessoryData.getAccessoryName2(), accessory.get(accessoryData.getAccessoryName2()));
                    }
                    if (accessory.containsKey(accessoryData.getAccessoryName3())) {
                        groupItem.put(accessoryData.getAccessoryName3(), accessory.get(accessoryData.getAccessoryName3()));
                    }
                    if (accessory.containsKey(accessoryData.getAccessoryName4())) {
                        groupItem.put(accessoryData.getAccessoryName4(), accessory.get(accessoryData.getAccessoryName4()));
                    }
                    if (accessory.containsKey(accessoryData.getAccessoryName5())) {
                        groupItem.put(accessoryData.getAccessoryName5(), accessory.get(accessoryData.getAccessoryName5()));
                    }
                    if (accessory.containsKey(accessoryData.getAccessoryName6())) {
                        groupItem.put(accessoryData.getAccessoryName6(), accessory.get(accessoryData.getAccessoryName6()));
                    }
                    if (accessory.containsKey(accessoryData.getAccessoryName7())) {
                        groupItem.put(accessoryData.getAccessoryName7(), accessory.get(accessoryData.getAccessoryName7()));
                    }
                    if (accessory.containsKey(accessoryData.getAccessoryName8())) {
                        groupItem.put(accessoryData.getAccessoryName8(), accessory.get(accessoryData.getAccessoryName8()));
                    }
                    if (accessory.containsKey(accessoryData.getAccessoryName9())) {
                        groupItem.put(accessoryData.getAccessoryName9(), accessory.get(accessoryData.getAccessoryName9()));
                    }
                }
                data.add(groupItem);
            });
        }
        return data;
    }

}
